﻿using System;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using RaytracerLib.RenderableObjects;
using RaytracerLib.MathLib;
using RaytracerLib;
using RaytracerLib.Layers;
using Raytracer.Generator;
using RaytracerLib.Layers.Interpolators;
using RaytracerLib.Layers.OverlayCorrectors;

namespace RaytracerTest
{
    [TestClass]
    public class LayersOperationsTest : TestBase
    {
        [TestMethod]
        public void Layers_Operations_Test()
        {
            SphereObject sphere = new SphereObject(Vector3.XAXIS, Vector3.YAXIS)
            {
                Pos = Vector3.ZERO,
                Radius = 1
            };

            var scene = new Scene();
            scene.RenderableObjects.Add(sphere);

            sphere.DefaultMaterial = TestMaterials.Shiny("shiny", ColorFloat.SRGB_Green);

            var ly1 = LayersFactory.Scale(null, new Vector2(2, 3));
            var ly11 = LayersFactory.Neg(ly1);
            var ly6 = new ColorArrayFloatFile("small_for_test1.bmp");
            var ly7 = new ColorArrayFloatFile("small_for_test1.bmp");
            var ly4 = new ColorArrayFloatFile("small_for_test1.bmp");
            ValueArrayFloatFile ly5 = (ValueArrayFloatFile)LayersFactory.ValuesFromFile(
                "small_for_test2.bmp", InterpolationMethod.Bilinear,
                OverlayMethod.Overlap);
            var ly3 = LayersFactory.Transparent(ly6, ly7, 0.1);
            var ly2 = LayersFactory.Transparent(ly3, ly4, ly5);
            var ly10 = LayersFactory.Solid(ColorFloat.SRGB_Red);
            var ly9 = LayersFactory.Add(ly10, ColorFloat.SRGB_Red);
            var ly8 = LayersFactory.Add(ly2, ly9);

            sphere.DefaultMaterial.Diffuse = ly11;

            Layer.InsertAfter(ly1, ly8);
            Assert.AreSame(ly1, ly8.Parent);
            Assert.AreSame(ly1.Children.First(), ly8);

            var arrays = Layer.GetAllArrays(ly11);
            Assert.IsTrue(arrays.Contains(ly6));
            Assert.IsTrue(arrays.Contains(ly7));
            Assert.IsTrue(arrays.Contains(ly4));
            Assert.IsTrue(arrays.Any(ar => Object.ReferenceEquals(ar, ly5)));
            Assert.AreEqual(4, arrays.Count);

            var leaves = Layer.GetLeaves(ly11);
            Assert.AreEqual(7, leaves.Count);
            Assert.IsTrue(leaves.Any(ar => Object.ReferenceEquals(ar, ly6)));
            Assert.IsTrue(leaves.Any(ar => Object.ReferenceEquals(ar, ly7)));
            Assert.IsTrue(leaves.Any(ar => Object.ReferenceEquals(ar, ly4)));
            Assert.IsTrue(leaves.Any(ar => Object.ReferenceEquals(ar, ly5)));
            Assert.IsTrue(leaves.Any(ar => Object.ReferenceEquals(ar, ly10)));

            Layer.SetScale(ly11, new Vector2(6, 7));
            Assert.AreEqual(new Vector2(6, 7), (ly1 as ScaleOperationLayer).Ratio);

            var ln1 = LayersFactory.Neg(null);
            Layer.InsertBefore(sphere.DefaultMaterial, ly11.Children.First(), ln1);
            Assert.AreSame(ly11, ln1.Parent);
            Assert.AreSame(ln1, ly1.Parent);
            Assert.AreSame(ln1, ly11.Children.First());
            Assert.AreSame(ln1.Children.First(), ly1);

            var ln2 = LayersFactory.Neg(null);
            Layer.InsertBefore(sphere.DefaultMaterial, ly11, ln2);
            Assert.AreSame(null, ln2.Parent);
            Assert.AreSame(ln2, ly11.Parent);
            Assert.AreSame(ly11, ln1.Parent);
            Assert.AreSame(ly11, ln2.Children.First());
            Assert.AreSame(ln1, ly11.Children.First());
        }
    }
}